﻿using System;
using Windows.UI.Xaml.Media;

namespace PanViewLibrary
{
    public static class TransformExtensions
    {
        public static void Append(this CompositeTransform j, CompositeTransform k)
        {
            InternalAppend(new WrappedCompositeTransform(j), new WrappedCompositeTransform(k));
        }

        public static void Append(this ICompositeTransform j, ICompositeTransform k)
        {
            InternalAppend(j, k);
        }

        public static void ZeroCenterPoint(this CompositeTransform t)
        {
            InternalZeroCenterPoint(new WrappedCompositeTransform(t));
        }

        public static void ZeroCenterPoint(this ICompositeTransform t)
        {
            InternalZeroCenterPoint(t);
        }

        public static void Reset(this CompositeTransform t)
        {
            InternalReset(new WrappedCompositeTransform(t));
        }

        public static void Reset(this ICompositeTransform t)
        {
            InternalReset(t);
        }

        public static void Copy(this CompositeTransform j, CompositeTransform k)
        {
            InternalCopy(new WrappedCompositeTransform(j), new WrappedCompositeTransform(k));
        }

        public static void Copy(this ICompositeTransform j, ICompositeTransform k)
        {
            InternalCopy(j, k);
        }

        static void InternalAppend(ICompositeTransform j, ICompositeTransform k)
        {
            var clonedK = new MockCompositeTransform(k); // do not modify k
            j.TranslateX *= clonedK.ScaleX;
            j.TranslateY *= clonedK.ScaleY;
            j.TranslateX += clonedK.CenterX * (1-clonedK.ScaleX);
            j.TranslateY += clonedK.CenterY * (1-clonedK.ScaleY);
            InternalZeroCenterPoint(j);
            InternalZeroCenterPoint(clonedK);
            InternalZeroedAppend(j, clonedK);
        }

        static void InternalZeroedAppend(ICompositeTransform j, ICompositeTransform k)
        {
            var d = Math.Sqrt(j.TranslateX * j.TranslateX + j.TranslateY * j.TranslateY);
            var a = Math.Atan2(j.TranslateY, j.TranslateX);
            a += k.Rotation * Math.PI / 180;
            var x = Math.Cos(a) * d;
            var y = Math.Sin(a) * d;
            j.Rotation += k.Rotation;
            j.TranslateX = k.TranslateX + x;
            j.TranslateY = k.TranslateY + y;
            j.ScaleX *= k.ScaleX;
            j.ScaleY *= k.ScaleY;
        }

        static void InternalZeroCenterPoint(ICompositeTransform t)
        {
            var d = Math.Sqrt(t.CenterX * t.CenterX + t.CenterY * t.CenterY);
            var b = Math.Atan2(-t.CenterY, -t.CenterX);
            var g = b + t.Rotation * Math.PI / 180;
            var Bx = -t.CenterX;
            var By = -t.CenterY;
            var Gx = Math.Cos(g) * d;
            var Gy = Math.Sin(g) * d;
            t.TranslateX += Gx - Bx;
            t.TranslateY += Gy - By;
            t.CenterX = 0;
            t.CenterY = 0;
        }

        static void InternalReset(ICompositeTransform t)
        {
            t.TranslateX = 0;
            t.TranslateY = 0;
            t.Rotation = 0;
            t.CenterX = 0;
            t.CenterY = 0;
            t.ScaleX = 1;
            t.ScaleY = 1;
            t.SkewX = 0;
            t.SkewY = 0;
        }

        static void InternalCopy(ICompositeTransform j, ICompositeTransform k)
        {
            j.TranslateX = k.TranslateX;
            j.TranslateY = k.TranslateY;
            j.Rotation = k.Rotation;
            j.CenterX = k.CenterX;
            j.CenterY = k.CenterY;
            j.ScaleX = k.ScaleX;
            j.ScaleY = k.ScaleY;
            j.SkewX = k.SkewX;
            j.SkewY = k.SkewY;
        }
    }
}
